/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package es.unavarra.mti.iws.gui;

import es.unavarra.mti.iws.Manager;
import es.unavarra.mti.iws.logic.editor.KeyboardEvent;
import es.unavarra.mti.iws.logic.editor.TouchEvent;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.RescaleOp;
import java.awt.image.VolatileImage;
import javax.swing.JPanel;

/**
 *
 * @author Marcelo
 */
public class RenderPanel extends JPanel implements ComponentListener, KeyListener, MouseListener, MouseMotionListener{
    private Manager manager;
    private float[] nullFloatArray = new float[]{0.0f,0.0f,0.0f};
    private VolatileImage backBuffer = null;
    private final Object graphicLock = new Object();
    
    /** Creates new form DrawPanel */
    public RenderPanel(Manager manager) {
        this.manager = manager;
        addComponentListener(this);
        addKeyListener(this);
        addMouseListener(this);
        addMouseMotionListener(this);
        initComponents();
    }


    public Object getGraphicLock() {
        return graphicLock;
    }

    private void createBackBuffer() {
        synchronized(graphicLock){
            if (backBuffer != null) {
                backBuffer.flush();
                backBuffer = null;
            }
            backBuffer = createVolatileImage(getWidth(), getHeight());
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 51, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 53, Short.MAX_VALUE)
        );
    }// </editor-fold>


    // Variables declaration - do not modify
    // End of variables declaration

    // <editor-fold defaultstate="collapsed" desc="draw system">
    @Override
    public void update(Graphics g) {
       paint(g);
    }

    @Override
    public void paint(Graphics g) {
        synchronized(graphicLock){
            if (backBuffer == null) {
                createBackBuffer();
            }
            do {
                // First, we validate the back buffer
                int valCode = backBuffer.validate(getGraphicsConfiguration());
                if (valCode == VolatileImage.IMAGE_INCOMPATIBLE) {
                    createBackBuffer();
                }

                // copy from the back buffer to the screen
                Graphics2D g2 = (Graphics2D)g;
                g2.drawImage(backBuffer, 0, 0, this);

                // Now we are done; or are we?  Check contentsLost() and loop as necessary
            } while (backBuffer.contentsLost());
        }
        Toolkit.getDefaultToolkit().sync();
    }

    public void clear() {
        Graphics2D graphics = backBuffer.createGraphics();
        graphics.clearRect(0, 0, getWidth(), getHeight());
    }

    public void pixel(float x, float y, int color) {
        Graphics2D graphics = backBuffer.createGraphics();
        graphics.setColor(new Color(color, true));
        graphics.drawOval((int) x, (int) y, 1, 1);
    }

    public void line(float x1, float y1, float x2, float y2, int color) {
        Graphics2D graphics = backBuffer.createGraphics();
        graphics.setColor(new Color(color, true));
        graphics.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
    }

    public void circle(float x, float y, float r, int color) {
        Graphics2D graphics = backBuffer.createGraphics();
        graphics.setColor(new Color(color, true));
        graphics.drawOval((int) (x - r), (int) (y - r), (int) r * 2, (int) r * 2);
    }

    public void circleFill(float x, float y, float r, int color) {
        Graphics2D graphics = backBuffer.createGraphics();
        graphics.setColor(new Color(color, true));
        graphics.fillOval((int) (x - r), (int) (y - r), (int) r * 2, (int) r * 2);
    }

    public void rectFill(float x, float y, float w, float h, int color) {
        Graphics2D graphics = backBuffer.createGraphics();
        graphics.setColor(new Color(color, true));
        graphics.fillRect((int) x, (int) y, (int) w, (int) h);
    }

    public void drawImage(BufferedImage img, float x, float y) {
        Graphics2D graphics = backBuffer.createGraphics();
        graphics.drawImage(img, null, (int) (x - img.getWidth() / 2), (int) (y - img.getHeight() / 2));
    }

    public void drawImageColored(BufferedImage img, float x, float y, int color) {
        Graphics2D graphics = backBuffer.createGraphics();
        float w2 = img.getWidth() / 2.0f;
        float h2 = img.getHeight() / 2.0f;
        int blue = (color >> 0) & 0xFF;
        int green = (color >> 8) & 0xFF;
        int red = (color >> 16) & 0xFF;
        int alpha = (color >> 24) & 0xff;


        BufferedImageOp trans = null;
        Composite composite = graphics.getComposite();
        if (alpha != 255) {
            graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha / 256.0f));
        }
        if (blue != 255 || green != 255 || red != 255) {
            float[] scaleFactors = new float[]{red / 256.0f, green / 256.0f, blue / 256.0f};
            trans = new RescaleOp(scaleFactors, nullFloatArray, null);
        }
        graphics.drawImage(img, trans, (int) (x - w2), (int) (y - h2));
        graphics.setComposite(composite);
    }


    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Events">
    public void keyTyped(KeyEvent e) {}

    public void keyPressed(KeyEvent e) {
        manager.addKeyEvent( new KeyboardEvent(KeyboardEvent.TYPE_DOWN, e.getKeyCode()) );

    }

    public void keyReleased(KeyEvent e) {
        manager.addKeyEvent( new KeyboardEvent(KeyboardEvent.TYPE_UP, e.getKeyCode()) );
    }


    public void mouseClicked(MouseEvent e) {}

    public void mousePressed(MouseEvent e) {
        manager.addTouchEvent( new TouchEvent(TouchEvent.TYPE_DOWN, 0,
                e.getX() ,
                e.getY() ));
        requestFocusInWindow();
    }

    public void mouseReleased(MouseEvent e) {
        manager.addTouchEvent( new TouchEvent(TouchEvent.TYPE_UP, 0,
                e.getX() ,
                e.getY() ));
    }

    public void mouseEntered(MouseEvent e) {}

    public void mouseExited(MouseEvent e) {}

    public void mouseDragged(MouseEvent e) {
        manager.addTouchEvent( new TouchEvent(TouchEvent.TYPE_DRAG, 0,
                e.getX() ,
                e.getY() ));
    }

    public void mouseMoved(MouseEvent e) {
        manager.addTouchEvent( new TouchEvent(TouchEvent.TYPE_MOVE, 0,
                e.getX() ,
                e.getY() ));
    }


    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Component view">
    public void componentResized(ComponentEvent e) {
            createBackBuffer();
    }

    public void componentMoved(ComponentEvent e) {}

    public void componentShown(ComponentEvent e) {}

    public void componentHidden(ComponentEvent e) {}

    // </editor-fold>
}
